package com.rui.singleton.main;

import com.rui.singleton.model.*;
import com.rui.singleton.obj.SafetyDangerLibrary;

/**
 * 单例模式
 * <p>
 * 适用场景：
 * 需要确保在任何情况下绝对只需要一个实例。如：ServletContext，ServletConfig，ApplicationContext，DBPool，ThreadPool等。
 * <p>
 * 优点：
 * 在内存中只有一个实例，减少了内存开销。
 * 可以避免对资源的多重占用。
 * 设置全局访问点，严格控制访问。
 * <p>
 * 缺点：
 * 没有接口，扩展困难。
 * 如果要扩展单例对象，只有修改代码，没有其它途径。
 *
 * @author ZhangRui
 * @date 2023/03/02 10:30
 **/
public class SingletonMain {

    public static void main(String[] args) throws Exception {

        // 饿汉式
        EagerSingleton eagerSingleton = EagerSingleton.getInstance();

        // 懒汉式
        LazySingleton lazySingleton = LazySingleton.getInstance();

        // 双重检验锁(double check lock)(DCL)
        DCLSingleton dclSingleton = DCLSingleton.getInstance();

        // 静态内部类
        StaticSingleton staticSingleton = StaticSingleton.getInstance();


        // 容器单例
        testContainerSingleton();

        // ThreadLocal单例
        testThreadLocalSingleton();
    }

    /**
     * 容器单例
     *
     * @throws Exception
     */
    private static void testContainerSingleton() throws Exception {
        // 容器单例
        SafetyDangerLibrary instance1 = (SafetyDangerLibrary) ContainerSingleton.getInstance(SafetyDangerLibrary.class);
        SafetyDangerLibrary instance2 = (SafetyDangerLibrary) ContainerSingleton.getInstance(SafetyDangerLibrary.class);
        // true
        System.out.println(instance1 == instance2);
    }

    /**
     * ThreadLocal单例
     */
    private static void testThreadLocalSingleton() {

        //        Thread-0-----com.ruoyi.library.domain.vo.ThreadLocalSingleton@53ac93b3
        //        Thread-1-----com.ruoyi.library.domain.vo.ThreadLocalSingleton@7fe11afc
        //        Thread-0-----com.ruoyi.library.domain.vo.ThreadLocalSingleton@53ac93b3
        //        Thread-1-----com.ruoyi.library.domain.vo.ThreadLocalSingleton@7fe11afc

        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "-----" + ThreadLocalSingleton.getInstance());
            System.out.println(Thread.currentThread().getName() + "-----" + ThreadLocalSingleton.getInstance());
        }).start();

        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "-----" + ThreadLocalSingleton.getInstance());
            System.out.println(Thread.currentThread().getName() + "-----" + ThreadLocalSingleton.getInstance());
        }).start();

    }

}
